#include "addresstablemodel.h"
#include "ipcoinunits.h"
#include "coincontroldialog.h"
#include "guiutil.h"
#include "optionsmodel.h"
#include "intangiblesentry.h"
#include "walletmodel.h"

#include "rpcserver.h"
#include "rpcclient.h"

#include "json/json_spirit.h"
#include <openssl/crypto.h>
#include "net.h"
#include <boost/lexical_cast.hpp>

std::string getRPCvalueHEX(std::string result, std::string label)
{
json_spirit::mValue v;
std::string outpt = "";
if (read(result,v))
{
json_spirit::mObject m1 = v.get_obj();
json_spirit::mArray a1 = m1.find("vout")->second.get_array();
json_spirit::mObject m2 = a1[0].get_obj();
json_spirit::mObject m3 = m2.find("scriptPubKey")->second.get_obj();
outpt = m3.find("type")->second.get_str();
if (outpt=="pubkeyhash")
{
	m2 = a1[1].get_obj();
	m3 = m2.find("scriptPubKey")->second.get_obj();
	cout << m3.find("hex")->second.get_str() << endl;
	outpt = m3.find("hex")->second.get_str();
}
else
{
	outpt = m3.find("hex")->second.get_str();
}

} //read ok
cout << outpt << endl;
return outpt;
} //end read HEX function

std::string getRPCvalueN(std::string result, std::string label)
{
json_spirit::mValue v;
std::string outpt = "";
int n;
if (read(result,v))
{
json_spirit::mObject m1 = v.get_obj();
json_spirit::mArray a1 = m1.find("vout")->second.get_array();
json_spirit::mObject m2 = a1[0].get_obj();
json_spirit::mObject m3 = m2.find("scriptPubKey")->second.get_obj();
outpt = m3.find("type")->second.get_str();
if (outpt=="pubkeyhash")
{
	m2 = a1[1].get_obj();
	n = m2.find("n")->second.get_int();
	outpt = boost::lexical_cast<string>(n);
}
else
{
	n = m2.find("n")->second.get_int();
	outpt = boost::lexical_cast<string>(n);
}

} //read ok
return outpt;
} //end read n function

std::string getRPCvalueVALUE(std::string result, std::string label)
{
json_spirit::mValue v;
std::string outpt = "";
double value;
if (read(result,v))
{
json_spirit::mObject m1 = v.get_obj();
json_spirit::mArray a1 = m1.find("vout")->second.get_array();
json_spirit::mObject m2 = a1[0].get_obj();
json_spirit::mObject m3 = m2.find("scriptPubKey")->second.get_obj();
outpt = m3.find("type")->second.get_str();
if (outpt=="pubkeyhash")
{
	m2 = a1[1].get_obj();
	value = m2.find("value")->second.get_real();
	outpt = boost::lexical_cast<string>(value);
}
else
{
	value = m2.find("value")->second.get_real();
	outpt = boost::lexical_cast<string>(value);
}

} //read ok
return outpt;
}

std::string getRPCvalueVALUE_TXIN(std::string result, std::string label)
{
json_spirit::mValue v;
std::string outpt = "";
double value = 0;
if (read(result,v))
{
json_spirit::mObject m1 = v.get_obj();
cout << "a1" <<endl;
json_spirit::mArray a1 = m1.find("vout")->second.get_array();
cout << "a" <<endl;
json_spirit::mObject m2 = a1[0].get_obj();
cout << "b" <<endl;
value = m2.find("value")->second.get_real();
cout << "c" <<endl;
} //read ok
outpt = boost::lexical_cast<string>(value);
cout << "d" <<endl;
return outpt;
}

std::string getRPCvalueADDRESS_IN(std::string result, std::string label)
{
json_spirit::mValue v;
std::string outpt = "";
if (read(result,v))
{
json_spirit::mObject m1 = v.get_obj();
json_spirit::mArray a1 = m1.find("vout")->second.get_array();
json_spirit::mObject m2 = a1[0].get_obj();
json_spirit::mObject m3 = m2.find("scriptPubKey")->second.get_obj();
outpt = m3.find("type")->second.get_str();
if (outpt=="scripthash")
{
	m2 = a1[1].get_obj();
	m3 = m2.find("scriptPubKey")->second.get_obj();
	json_spirit::mArray a2 = m3.find("addresses")->second.get_array();
	outpt = a2[0].get_str();
}
else
{
	json_spirit::mArray a2 = m3.find("addresses")->second.get_array();
	outpt = a2[0].get_str();
}
}
return outpt;
}

std::string getRPCvalueADDRESS(std::string result, std::string label)
{
json_spirit::mValue v;
std::string outpt = "";
if (read(result,v))
{
json_spirit::mObject m1 = v.get_obj();
json_spirit::mArray a1 = m1.find("vout")->second.get_array();
json_spirit::mObject m2 = a1[0].get_obj();
json_spirit::mObject m3 = m2.find("scriptPubKey")->second.get_obj();
outpt = m3.find("type")->second.get_str();
if (outpt=="pubkeyhash")
{
	m2 = a1[1].get_obj();
	m3 = m2.find("scriptPubKey")->second.get_obj();
	json_spirit::mArray a2 = m3.find("addresses")->second.get_array();
	outpt = a2[0].get_str();
}
else
{
	json_spirit::mArray a2 = m3.find("addresses")->second.get_array();
	outpt = a2[0].get_str();
}
}
return outpt;
}

//not really from grouping any more, using the more reliable command
void getRPCvalueADDRESSESfromGROUPING(std::string result, std::vector<std::string> &out)
{
json_spirit::mValue v;
if (read(result,v))
{
json_spirit::mArray a1 = v.get_array();
for (unsigned int i = 0; i < a1.size(); i++)
{
	json_spirit::mObject o1 = a1[i].get_obj();
	std::string addr = o1.find("address")->second.get_str();
	cout << "Addr: " + addr << endl;
	out.push_back(addr);	
}
}

}

std::string getRPCvalueTXID_IN(std::string result, std::string label)
{
json_spirit::mValue v;
std::string outpt = "";
if (read(result,v))
{
json_spirit::mObject m1 = v.get_obj();
json_spirit::mArray a1 = m1.find("vin")->second.get_array();
json_spirit::mObject m2 = a1[0].get_obj();
outpt = m2.find("txid")->second.get_str();
} //read ok
return outpt;
}

std::string getRPCvalue(std::string result, std::string label)
{
json_spirit::mValue v;
std::string outpt = "";
if (read(result,v))
{
json_spirit::mObject o = v.get_obj();
outpt = o.find(label)->second.get_str();
}
return outpt;
}

bool getRPCvaluebool(std::string result, std::string label)
{
json_spirit::mValue v;
bool outpt = false;
if (read(result,v))
{
json_spirit::mObject o = v.get_obj();
outpt = o.find(label)->second.get_bool();
}
return outpt;
}

//format the contract into data that payer can send to payee
std::string buildExchangeableTransaction(std::string transaction, std::string txid, std::string n, std::string hex, std::string redeemScript)
{
	std::string out ("");
	out = transaction + "/" + txid + "/" + n + "/" + hex + "/" + redeemScript;
	return out;
}

void decodeExchangeableTransaction(std::string &transaction, std::string &txid, std::string &n, std::string &hex, std::string &redeemScript)
{
int cursor = 0;
cursor = transaction.find("/")-1;
std::string trans = transaction.substr(0,cursor) + "0";
transaction = transaction.substr(cursor);
cursor = transaction.find("/");
txid = transaction.substr(cursor+1,transaction.find("/",cursor+2)-2);
transaction = transaction.substr(transaction.find("/",cursor+2));
cursor = transaction.find("/");
n = transaction.substr(cursor+1,transaction.find("/",cursor+2)-1);
transaction = transaction.substr(transaction.find("/",cursor+2));
cursor = transaction.find("/");
hex = transaction.substr(cursor+1,transaction.find("/",cursor+2)-1);
transaction = transaction.substr(transaction.find("/",cursor+2));
cursor = transaction.find("/");
redeemScript = transaction.substr(cursor+1,transaction.find("/",cursor+2)-1);
transaction = trans;
}

bool ReadLine(SOCKET hSocket, string& strLine)
{
    strLine = "";
    while (true)
    {
        char c;
        int nBytes = recv(hSocket, &c, 1, 0);
        if (nBytes > 0)
        {
            if (c == '\n')
                continue;
            if (c == '\r')
                return true;
            strLine += c;
            if (strLine.size() >= 9000)
                { return true; }
        }
        else if (nBytes <= 0)
        {
            boost::this_thread::interruption_point();
            if (nBytes < 0)
            {
                int nErr = WSAGetLastError();
                if (nErr == WSAEMSGSIZE)
                    continue;
                if (nErr == WSAEWOULDBLOCK || nErr == WSAEINTR || nErr == WSAEINPROGRESS)
                {
                    MilliSleep(10);
                    continue;
                }
            }
            if (!strLine.empty())
                return true;
            if (nBytes == 0)
            {
                // socket closed
                return false;
            }
            else
            {
                // socket error
                return false;
            }
        }
    }
}

bool WebRequest(const CService& addrConnect, const char* pszGet, string& strContent)
{
    SOCKET hSocket;
    if (!ConnectSocket(addrConnect, hSocket))
        return false;
    send(hSocket, pszGet, strlen(pszGet), MSG_NOSIGNAL);

    string strLine;
    while (ReadLine(hSocket, strLine))
	strContent += strLine;
            closesocket(hSocket);
    closesocket(hSocket);
    return true;
}

bool parseCommandLine2(std::vector<std::string> &args, const std::string &strCommand)
{
    enum CmdParseState
    {
        STATE_EATING_SPACES,
        STATE_ARGUMENT,
        STATE_SINGLEQUOTED,
        STATE_DOUBLEQUOTED,
        STATE_ESCAPE_OUTER,
        STATE_ESCAPE_DOUBLEQUOTED
    } state = STATE_EATING_SPACES;
    std::string curarg;
    foreach(char ch, strCommand)
    {
        switch(state)
        {
        case STATE_ARGUMENT: // In or after argument
        case STATE_EATING_SPACES: // Handle runs of whitespace
            switch(ch)
            {
            case '"': state = STATE_DOUBLEQUOTED; break;
            case '\'': state = STATE_SINGLEQUOTED; break;
            case '\\': state = STATE_ESCAPE_OUTER; break;
            case ' ': case '\n': case '\t':
                if(state == STATE_ARGUMENT) // Space ends argument
                {
                    args.push_back(curarg);
                    curarg.clear();
                }
                state = STATE_EATING_SPACES;
                break;
            default: curarg += ch; state = STATE_ARGUMENT;
            }
            break;
        case STATE_SINGLEQUOTED: // Single-quoted string
            switch(ch)
            {
            case '\'': state = STATE_ARGUMENT; break;
            default: curarg += ch;
            }
            break;
        case STATE_DOUBLEQUOTED: // Double-quoted string
            switch(ch)
            {
            case '"': state = STATE_ARGUMENT; break;
            case '\\': state = STATE_ESCAPE_DOUBLEQUOTED; break;
            default: curarg += ch;
            }
            break;
        case STATE_ESCAPE_OUTER: // '\' outside quotes
            curarg += ch; state = STATE_ARGUMENT;
            break;
        case STATE_ESCAPE_DOUBLEQUOTED: // '\' in double-quoted text
            if(ch != '"' && ch != '\\') curarg += '\\'; // keep '\' for everything but the quote and '\' itself
            curarg += ch; state = STATE_DOUBLEQUOTED;
            break;
        }
    }
    switch(state) // final state
    {
    case STATE_EATING_SPACES:
        return true;
    case STATE_ARGUMENT:
        args.push_back(curarg);
        return true;
    default: // ERROR to end in one of the other states
        return false;
    }
}


std::string executeRPCcommand(QString command)
{
	std::vector<std::string> args;
	    parseCommandLine2(args, command.toStdString());

	json_spirit::Value result = tableRPC.execute(args[0],RPCConvertValues(args[0], std::vector<std::string>(args.begin() + 1, args.end())));
         
	std::string strPrint;

if (result.type() == json_spirit::null_type)
            strPrint = "";
        else if (result.type() == json_spirit::str_type)
            strPrint = result.get_str();
        else
            strPrint = write_string(result, true);

//QString qstr = QString::fromStdString(strPrint);
	return strPrint;
}

